package org.example.Proxy;

import cn.hutool.core.lang.Console;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;

import java.net.InetSocketAddress;

// HttpProxyServerHandler 继承自 ChannelInboundHandlerAdapter，
// 用于处理代理服务器接收到的 HTTP 请求。
public class HttpProxyServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

    // 声明一个 EventLoopGroup 对象，用于处理 I/O 操作。
    private final EventLoopGroup workerGroup;

    // 构造方法，参数是 EventLoopGroup，通过构造方法传递 I/O 处理组。
    public HttpProxyServerHandler(EventLoopGroup workerGroup) {
        this.workerGroup = workerGroup;
    }

    // 重写 channelRead 方法，该方法在 Channel 读取到数据时被触发。
    @Override
    public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {
        if (msg != null) {

            String host = null;
            String starts = null;
            Console.log(msg.uri());

            int port;
            // 根据请求 URI 的前缀决定转发到哪个服务。
            if (msg.uri().startsWith("/ui")) {
                host = "localhost";
                port = 3000;
                starts = "/ui";
            } else if (msg.uri().startsWith("/server")) {
                host = "localhost";
                port = 8000;
                starts = "/server";
            } else {
                // 如果请求 URI 不匹配任何服务，发送 BAD_REQUEST 响应。
                sendErrorResponse(ctx, HttpResponseStatus.BAD_REQUEST);
                return;
            }

            // 修改请求 URI，移除代理特定的前缀。
            String modifiedUri = msg.uri().substring(starts.length());

            FullHttpRequest modifiedRequest = msg.copy().setUri(modifiedUri).retain();

            // 将修改后的请求转发到目标服务器。
            forwardRequest(ctx, host, port, modifiedRequest);
        }
    }

    // 私有方法，用于转发请求到目标服务器。
    private void forwardRequest(ChannelHandlerContext ctx, String host, int port, FullHttpRequest modifiedRequest) {
        Bootstrap bootstrap = new Bootstrap();
        // 配置 Bootstrap，设置 I/O 处理组、Channel 类型和处理器。
        bootstrap.group(workerGroup)
                .channel(ctx.channel().getClass())
                .handler(new HttpProxyClientHandler(ctx));

        // 连接到目标服务器，并获取 ChannelFuture。
        ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));
        // 设置连接监听器，当连接成功时，写入并发送修改后的请求；当连接失败时，关闭当前 Channel。
        future.addListener((ChannelFutureListener) channelFuture -> {
            if (channelFuture.isSuccess()) {
                channelFuture.channel().writeAndFlush(modifiedRequest);
            } else {
                ctx.close();
            }
        });
    }

    // 私有方法，用于发送错误响应。
    private void sendErrorResponse(ChannelHandlerContext ctx, HttpResponseStatus status) {
        // 创建错误响应对象，并设置状态码、响应体和头信息。
        FullHttpResponse response = new DefaultFullHttpResponse(
                HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer("Bad Request", CharsetUtil.UTF_8));
        response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
        // 写入并发送错误响应，然后关闭 Channel。
        ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    }
}